Skip to content

feat(http/unstable): add RFC 9421 message signatures#7039

Open
tomas-zijdemans wants to merge 12 commits intodenoland:mainfrom
tomas-zijdemans:message-signatures
Open

feat(http/unstable): add RFC 9421 message signatures#7039
tomas-zijdemans wants to merge 12 commits intodenoland:mainfrom
tomas-zijdemans:message-signatures

Conversation

@tomas-zijdemans
Copy link
Copy Markdown
Contributor

@tomas-zijdemans tomas-zijdemans commented Mar 10, 2026

Add HTTP Message Signatures (RFC 9421) for signing and verifying HTTP requests and responses. Builds on the structured fields module (RFC 8941) already in std.

Coverage is as good as I can get it. There are a few lines of unreachable code.

@tomas-zijdemans tomas-zijdemans requested a review from kt3k as a code owner March 10, 2026 11:38
@github-actions github-actions bot added the http label Mar 10, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 10, 2026

Codecov Report

❌ Patch coverage is 98.67550% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.47%. Comparing base (a3a6ef6) to head (9eb6880).

Files with missing lines Patch % Lines
http/unstable_message_signatures.ts 98.67% 2 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7039      +/-   ##
==========================================
+ Coverage   94.43%   94.47%   +0.04%     
==========================================
  Files         630      631       +1     
  Lines       50566    51170     +604     
  Branches     8969     9164     +195     
==========================================
+ Hits        47750    48345     +595     
- Misses       2247     2249       +2     
- Partials      569      576       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough implementation! A few things to address:

badge.svg changes don't belong in this PR — The reformatting of the SVG is unrelated to message signatures. Please drop it from the branch (or submit separately).

Comment thread http/unstable_message_signatures.ts
Comment thread http/unstable_message_signatures.ts
Comment thread http/unstable_message_signatures.ts
Comment thread http/unstable_message_signatures.ts
@tomas-zijdemans
Copy link
Copy Markdown
Contributor Author

tomas-zijdemans commented Apr 12, 2026

T%hanks for the feedback!

  • Revert unrelated badge.svg change. Ooops! 🫣
  • Fix silent ECDSA curve fallback
  • Fix same class of bug for HMAC, RSA-PSS, and RSASSA-PKCS1-v1_5
  • Document ;bs limitation: add warnings in JSDoc
  • Add RFC citation for duplicate @query-param rejection. The throw is mandated by RFC 9421 section 2.2.8 ("the named query parameter MUST NOT be included")
  • Remove redundant ?? undefined in verifyMessage.
  • Add tests. Coverage can't reach 100% becuase of unreachable code

Copy link
Copy Markdown
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous round's feedback is fully addressed (ECDSA/HMAC/RSA-PSS throws, ;bs docs, @query-param RFC citation). This is a solid RFC 9421 implementation — well-structured, thorough tests, good use of the existing structured fields module.

A couple of things I'd like addressed before approving:

// expose getAll(). Splitting on ", " is therefore the best we can do, but
// it will mishandle single header values that contain a literal ", " (e.g.
// the Date header). Avoid using ;bs on such fields.
const values = headerValue.split(", ");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ;sf resolution tries Dictionary → List → Item. Tests cover Dictionary and Item fallback paths, but there's no test for a header that fails Dictionary parse but succeeds as a List (e.g. a header like "1, 2, 3" or "(a b), (c d)"). That List branch is untested — please add a test case.

Comment on lines +888 to +891
* @param message The HTTP request or response to verify.
* @param keyLookup Resolves a key identifier to a CryptoKey, or `null` if the
* key is not found. When the signature has no `keyid` parameter, the empty
* string `""` is passed.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the message already has a signature with the same label (e.g. default "sig"), appendHeader will produce a Signature-Input dictionary with duplicate keys. Per RFC 8941, the last value wins on parse, so the old signature is silently replaced while its byte sequence lingers in the Signature header.

Consider either:

  • Checking for label conflicts and throwing, or
  • Documenting in SignatureParams.label that the caller is responsible for uniqueness

The multi-signature test uses distinct labels and works correctly, so this only matters for the default-label case with pre-signed messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants